From: Keir Fraser Date: Mon, 20 Sep 2010 19:11:43 +0000 (+0100) Subject: x86: Retry do_mmu_update() a few times when called on a pte whose type is in flux. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~11456 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22Dat/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22Dat?a=commitdiff_plain;h=89acd8b4d60220b35bf97d94fe55a5cba47a5048;p=xen.git x86: Retry do_mmu_update() a few times when called on a pte whose type is in flux. This can really happen -- all our PV Linux kernels have a race between vmalloc_sync_all() and pgdir pinning/unpinning. The former is protected by pgd_lock while the latter by mm->page_table_lock. Hence they can happen concurrently, and vmalloc_sync_all() can attempt to set_pmd() on a page directory which is in the process of being pinned. This can confuse the hypervisor which may see a type change, and hence fail do_mmu_update(). Until this patch. :-) Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 96344db47e..b75763b5bc 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3414,6 +3414,7 @@ int do_mmu_update( case MMU_NORMAL_PT_UPDATE: case MMU_PT_UPDATE_PRESERVE_AD: { + unsigned int retries = 0; p2m_type_t p2mt; rc = xsm_mmu_normal_update(d, pg_owner, req.val); @@ -3445,6 +3446,7 @@ int do_mmu_update( (unsigned long)(req.ptr & ~PAGE_MASK)); page = mfn_to_page(mfn); + retry: if ( page_lock(page) ) { switch ( page->u.inuse.type_info & PGT_type_mask ) @@ -3601,6 +3603,11 @@ int do_mmu_update( v, va, req.val, _mfn(mfn)); put_page_type(page); } + else if ( retries++ < 5 ) + { + /* Page type can be in flux, so we retry a few times. */ + goto retry; + } unmap_domain_page_with_cache(va, &mapcache); put_page(page);